using System;
using System.Linq;
using System.Collections.Generic;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Kiiro.Common.Entities;
using Kiiro.Common.Interfaces;
using Kiiro.Common.Utility;
using Kiiro.ExceptionManagement;
using Permissions = Kiiro.Common.Utility.Constants.Permissions;

namespace Kiiro.Model
{
    /// <summary>
    /// Kiiro Licensing Model
    /// </summary>
    public class LicensingModel
    {
        internal static bool ValidateLicenseKeys ( IPermissions iPermissions, Guid siteCollectionId, string serverRelativeUrl )
        {
            bool valid = false;
            bool isKeyExpired = true;
            bool overProjectLimit = true;
            bool overUserLimit = true;

            try
            {
                LicensingManifest allKeysManifest = GetAllKeysManifest ( iPermissions, siteCollectionId, serverRelativeUrl );

                if ( allKeysManifest != null )
                {
                    valid = true;
                    isKeyExpired = allKeysManifest.ExpiryDate.Date < DateTime.Now.Date;

                    int openProjectsCount = GetOpenProjectsCount ( siteCollectionId, serverRelativeUrl );
                    overProjectLimit = openProjectsCount > allKeysManifest.OpenProjectsLimit;

                    int activeUsersCount = GetActiveUsersCount ( siteCollectionId, serverRelativeUrl );
                    overUserLimit = activeUsersCount > allKeysManifest.ActiveUsersLimit;

                    // trying to create a Project or User. Valid when count is less than or equal to limit
                    if ( iPermissions != null && iPermissions is Project )
                    {
                        valid = openProjectsCount <= allKeysManifest.OpenProjectsLimit;
                    }
                    else if ( iPermissions != null && iPermissions is User )
                    {
                        valid = activeUsersCount <= allKeysManifest.ActiveUsersLimit;
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( new Exception ( Permissions.ErrorMessages.ValidationError, ex ), true );
            }

            if ( iPermissions != null )
                iPermissions.LicenseKeyBits = new List<bool> ( ) { isKeyExpired, overProjectLimit, overUserLimit };

            return valid && iPermissions.LicenseKeyBits.Count ( l => l == false ) == 3; //!( isKeyExpired == false & overProjectLimit == false & overUserLimit == false );// valid;
        }

        public static LicensingManifest GetAllKeysManifest ( IPermissions iPermissions, Guid siteCollectionId, string serverRelativeUrl )
        {
            LicensingManifest allKeysManifest = null;

            List<string> licenseKeys = new List<string> ( );
            string instanceLicenseCode = SPHelpers.GetWebId ( siteCollectionId, serverRelativeUrl, true ).ToString ( );
            string serverLicenseCode = SPFarm.Local.Id.ToString ( );
            
            Setup setup = iPermissions != null && iPermissions is Setup ? ( Setup ) iPermissions :
                SetupModel.GetMidoriSetup ( siteCollectionId, serverRelativeUrl );

            if ( setup != null && !string.IsNullOrEmpty ( setup.LicenseKey ) )
                licenseKeys.AddRange ( setup.LicenseKey.Split ( new char [ ] { ',' }, StringSplitOptions.RemoveEmptyEntries ).Distinct ( ) );

            foreach ( string licenseKey in licenseKeys )
            {
                LicensingManifest manifest = LicensingManifest.GetLicensingManifest ( licenseKey ) ?? new LicensingManifest ( );

                if ( ( manifest.IsServerLicense && manifest.InstallCode == serverLicenseCode ) ||
                    ( !manifest.IsServerLicense && manifest.InstallCode == instanceLicenseCode ) )
                {
                    if ( manifest.ExpiryDate != null && manifest.ExpiryDate != DateTime.MinValue &&
                        DateTime.Today.Date.CompareTo ( manifest.ExpiryDate.Date ) < 0 )
                    {
                        if ( allKeysManifest != null )
                        {
                            allKeysManifest.OpenProjectsLimit += manifest.OpenProjectsLimit;
                            allKeysManifest.ActiveUsersLimit += manifest.ActiveUsersLimit;
                        }
                        else
                        {
                            allKeysManifest = manifest;
                        }

                        allKeysManifest.IsServerLicense = allKeysManifest.IsServerLicense || manifest.IsServerLicense;
                    }
                }
            }

            // no valid keys were found, set to default key values
            bool hasKeys = true;
            if ( allKeysManifest == null )
            {
                allKeysManifest = new LicensingManifest { ActiveUsersLimit = 3, OpenProjectsLimit = 10, InstallCode = instanceLicenseCode };
                hasKeys = false;
            }

            DateTime created;
            using ( SPWeb web = SPHelpers.GetPortalWeb ( siteCollectionId, serverRelativeUrl ) ) { created = web.Created.ToLocalTime ( ); }
            TimeSpan span = new TimeSpan ( );
            span = DateTime.Now.Date - created.Date;

            if ( span.Days > 15 && !hasKeys )                                  // If it has been more than 15 days since installation and install code is the only key
                allKeysManifest.ExpiryDate = DateTime.Today.AddDays ( -1 );    // expire the license by setting expiration date to yesterday.
            else
                allKeysManifest.ExpiryDate = DateTime.Today.Date;           // AllKeysManifest must be re-calculated on a daily basis due to the possibility of multiple expiry dates

            return allKeysManifest;
        }

        public static int GetOpenProjectsCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            int count = 0;
            object temp = CacheHelper.GetPortalCache ( Constants.CacheKeys.OpenProjectsCount, siteCollectionId, serverRelativeUrl );

            if ( temp != null )
            {
                count = ( int ) temp;
            }

            if (count <= 0)
            {
                count = ProjectsModel.GetNumberOfOpenProjects ( siteCollectionId, serverRelativeUrl );
                CacheHelper.UpdatePortalCache(Constants.CacheKeys.OpenProjectsCount, count, siteCollectionId, serverRelativeUrl);
            }

            return count;
        }

        public static void InvalidateOpenProjectsCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            CacheHelper.UpdatePortalCache ( Constants.CacheKeys.OpenProjectsCount, -1, siteCollectionId, serverRelativeUrl );
        }

        public static int GetActiveUsersCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            int count = 0;

            bool hasUniquePermissions = PermissionsModel.PortalWebHasUniquePermissions ( siteCollectionId, serverRelativeUrl );

            object temp = hasUniquePermissions ?
                CacheHelper.GetPortalCache(Constants.CacheKeys.ActiveUsersCount, siteCollectionId, serverRelativeUrl) :
                CacheHelper.GetPortalParentCache(Constants.CacheKeys.ActiveUsersCount, siteCollectionId, serverRelativeUrl);

            if ( temp != null )
            {
                count = ( int ) temp;
            }

            if (count<=0)
            {
                if ( hasUniquePermissions )
                {
                    count = UserModel.GetActiveUsers ( siteCollectionId, serverRelativeUrl ).Count;
                    CacheHelper.UpdatePortalCache(Constants.CacheKeys.ActiveUsersCount, count, siteCollectionId, serverRelativeUrl);
                }
                else
                {
                    List<int> userIds = UserModel.GetUsersFromSPGroups ( siteCollectionId, serverRelativeUrl )
                        .Select ( x => x.Id ).Distinct ( ).ToList ( );

                    count = UserModel.GetUsersByIds ( userIds, siteCollectionId, serverRelativeUrl )
                        .Where ( x => !x.IsSharePointAccount && !x.IsADGroup ).Count ( );

                    CacheHelper.UpdatePortalParentCache ( Constants.CacheKeys.ActiveUsersCount, count, siteCollectionId, serverRelativeUrl );
                }
            }

            return count;
        }

        public static void InvalidateActiveUsersCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            bool hasUniquePermissions = PermissionsModel.PortalWebHasUniquePermissions ( siteCollectionId, serverRelativeUrl );

            if ( hasUniquePermissions )
                CacheHelper.UpdatePortalCache ( Constants.CacheKeys.ActiveUsersCount, -1, siteCollectionId, serverRelativeUrl );
            else
                CacheHelper.UpdatePortalParentCache ( Constants.CacheKeys.ActiveUsersCount, -1, siteCollectionId, serverRelativeUrl );
        }

        internal static bool IncrementOpenProjectCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            bool cancel = false;
            int count = GetOpenProjectsCount ( siteCollectionId, serverRelativeUrl );
            LicensingManifest allKeysManifest = GetAllKeysManifest ( null, siteCollectionId, serverRelativeUrl );

            if ( count < allKeysManifest.OpenProjectsLimit )
            {
                count += 1;
                CacheHelper.UpdatePortalCache(Constants.CacheKeys.OpenProjectsCount, count, siteCollectionId, serverRelativeUrl);
            }
            else
            {
                cancel = true;
            }

            return cancel;
        }

        internal static bool DecrementOpenProjectCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            bool cancel = false;
            int count = GetOpenProjectsCount ( siteCollectionId, serverRelativeUrl );

            if ( count > 0 )
            {
                count -= 1;
                CacheHelper.UpdatePortalCache(Constants.CacheKeys.OpenProjectsCount, count, siteCollectionId, serverRelativeUrl);
            }
            else
            {
                cancel = true;
            }

            return cancel;
        }

        internal static bool IncrementActiveUsersCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            bool cancel = false;
            bool hasUniquePermissions = PermissionsModel.PortalWebHasUniquePermissions ( siteCollectionId, serverRelativeUrl );
            int count = GetActiveUsersCount ( siteCollectionId, serverRelativeUrl );
            LicensingManifest allKeysManifest = GetAllKeysManifest ( null, siteCollectionId, serverRelativeUrl );

            if ( count < allKeysManifest.ActiveUsersLimit )
            {
                count += 1;
                if ( hasUniquePermissions )
                    CacheHelper.UpdatePortalCache(Constants.CacheKeys.ActiveUsersCount, count, siteCollectionId, serverRelativeUrl);
                else
                    CacheHelper.UpdatePortalParentCache(Constants.CacheKeys.ActiveUsersCount, count, siteCollectionId, serverRelativeUrl);
            }
            else
            {
                cancel = true;
            }

            return cancel;
        }

        internal static bool DecrementActiveUsersCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            bool cancel = false;
            bool hasUniquePermissions = PermissionsModel.PortalWebHasUniquePermissions ( siteCollectionId, serverRelativeUrl );
            int count = GetActiveUsersCount ( siteCollectionId, serverRelativeUrl );
            LicensingManifest allKeysManifest = GetAllKeysManifest ( null, siteCollectionId, serverRelativeUrl );

            if ( count > 0 )
            {
                count -= 1;
                if ( hasUniquePermissions )
                    CacheHelper.UpdatePortalCache(Constants.CacheKeys.ActiveUsersCount, count, siteCollectionId, serverRelativeUrl);
                else
                    CacheHelper.UpdatePortalParentCache(Constants.CacheKeys.ActiveUsersCount, count, siteCollectionId, serverRelativeUrl);
            }
            else
            {
                cancel = true;
            }

            return cancel;
        }

        public static bool CanIncrementOpenProjectCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            int count = GetOpenProjectsCount ( siteCollectionId, serverRelativeUrl );
            LicensingManifest allKeysManifest = GetAllKeysManifest ( null, siteCollectionId, serverRelativeUrl );

            return allKeysManifest != null && count < allKeysManifest.OpenProjectsLimit;
        }

        public static bool CanIncrementActiveUsersCount ( Guid siteCollectionId, string serverRelativeUrl )
        {
            int count = GetActiveUsersCount ( siteCollectionId, serverRelativeUrl );
            LicensingManifest allKeysManifest = GetAllKeysManifest ( null, siteCollectionId, serverRelativeUrl );

            return allKeysManifest != null && count < allKeysManifest.ActiveUsersLimit;
        }

        public static bool HasUnlimitedUsers ( Guid siteCollectionId, string serverRelativeUrl )
        {
            LicensingManifest allKeysManifest = GetAllKeysManifest ( null, siteCollectionId, serverRelativeUrl );
            return allKeysManifest != null && double.IsInfinity ( allKeysManifest.ActiveUsersLimit );
        }

        public static bool HasUnlimitedProjects ( Guid siteCollectionId, string serverRelativeUrl )
        {
            LicensingManifest allKeysManifest = GetAllKeysManifest ( null, siteCollectionId, serverRelativeUrl );
            return allKeysManifest != null && double.IsInfinity ( allKeysManifest.OpenProjectsLimit );
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.Model/LicensingModel.cs $
 * 
 * 28    2/08/10 5:04p Camerons
 * 
 * 27    1/25/10 1:17p Camerons
 * 
 * 26    1/12/10 12:03p Camerons
 * 
 * 25    4/01/10 12:03p Adamw
 * 
 * 24    26/11/09 10:35a Camerons
 * 
 * 23    17/11/09 6:46p Camerons
 * 
 * 22    6/11/09 8:54p Camerons
 * 
 * 21    28/10/09 3:13p Camerons
 * 
 * 20    28/10/09 11:23a Camerons
 * 
 * 19    26/10/09 1:53p Camerons
 * Fogbugz case #335 - Update logic in CanUserCreateItem for Portal Owners
 * 
 * 18    21/10/09 3:06p Shafia
 * using CacheKeys constants instead of hard coding key names
 * 
 * 17    8/10/09 7:38p Camerons
 * Updated GetAllKeysManifest to enable Server licensing
 * 
 * 16    8/10/09 7:25p Camerons
 * 
 * 15    8/10/09 6:41p Camerons
 * Updates for Server License
 * 
 * 14    7/10/09 12:14p Camerons
 * Add missing System.Linq namesapce
 * 
 * 13    7/10/09 12:09p Camerons
 * Updated reading and saving of cached user count when Portal web has
 * inherited permissions
 * 
 * 12    5/10/09 11:07a Camerons
 * RE: Create user on demand, checks for HasUnlimitedUser before creating
 * 
 * 11    28/09/09 10:13a Camerons
 * 
 * 10    21/09/09 3:30p Camerons
 * First batch of changes for 1.1.x.x - Security groups update
 * 
 * 9     9/01/09 11:37a Stefanf
 * 
 * 8     17/08/09 10:29a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/